Programs written in the Java programming language (Java is a trademark of Sun Microsystems Inc) are generally run in a virtual machine environment, rather than directly on hardware. Thus a Java program is typically compiled into byte-code form, and then interpreted by a Java virtual machine (VM) into hardware commands for the platform on which the Java VM is executing. The Java VM itself is an application running on the underlying operating system. An important advantage of this approach is that Java applications can then run on a very wide range of platforms.
Java is an object-oriented language. Thus a Java program is formed from a set of class files having methods that represent sequences of instructions. A hierarchy of classes can be defined, with each class inheriting properties (including methods) from those classes which are above it in the hierarchy. For any given class in the hierarchy, its descendants (i.e. below it) are called subclasses, whilst its ancestors (i.e. above it) are called superclasses. At run-time objects are created as instantiations of these class files, and indeed the class files themselves are effectively loaded as objects. One Java object can call a method in another Java object. In recent years the Java environment has become very popular, and is described in many books, for example “Exploring Java” by Niemeyer and Peck, O'Reilly & Associates, 1996, USA, and “The Java Virtual Machine Specification” by Lindholm and Yellin, Addison-Wedley, 1997, USA.
The standard Java VM architecture is generally designed to run only a single application, although this can be multi-threaded. In a server environment used for database transactions and such-like, each transaction is typically performed as a separate application, rather than as different threads within an application. This is to ensure that every transaction starts with the Java VM in a clean state. In other words, a new Java VM is started for each transaction (i.e. for each new Java application). Unfortunately however this results in an initial delay in running the application (the reasons for this will be described in more detail later). The overhead due to this frequent starting and then stopping a Java VM as successive transactions are processed is significant, and seriously degrades the scalability of Java server solutions.
Various attempts have been made to mitigate this problem. EP-962860-A describes a process whereby one Java VM can fork into a parent and a child process, this being quicker than setting up a fresh Java VM. The ability to run multiple processes in a Java-like system, thereby reducing overhead per application, is described in “Processes in KaffeOS: Isolation, Resource Management, and Sharing in Java” by G back, W Hsieh, and J Lepreau (see the file/flux/papers/kaffeos-osdi00/main.html) at cs.utah.edu).
Another approach is described in “Oracle JServer Scalability and Performance” by Jeremy Litzt, July 1999 (see the file/database/documents/j server_scalability_and_performance twp.pdf at oracle.com). The JServer product available from Oracle Corporation, USA, supports the concept of multiple sessions (a session effectively representing a transaction or application), each session including a JServer session. Each individual session appears to its JServer client to be a dedicated conventional Java VM.
U.S. patent application Ser. No. 09/304,160, filed 30 Apr. 1999 now U.S. Pat. No. 6,694,346 (“A long Running Reusable Extendible Virtual Machine”), assigned to IBM Corporation, discloses a virtual machine having two types of heap, a private heap and a shared heap. The former is intended primarily for storing application classes, whilst the latter is intended primarily for storing system classes and, as its name implies, is accessible to multiple VMs. A related idea is described in “Building a Java virtual machine for server applications: the JVM on OS/390” by Dillenberger et al, IBM Systems Journal, Vol 39/1, Jan. 2000.
The above documents are focused primarily on the ability to easily run multiple Java VMs in parallel. A different (and potentially complementary) approach is based on a serial rather than parallel configuration. Thus it is desirable to run repeated transactions (i.e. applications) on the same Java VM, since this could avoid having to reload all the system classes at the start of each application. However, one difficulty with this is that each application expects to run on a fresh, clean, Java VM. There is a danger with serial re-use of a Java VM that the state left from a previous transaction somehow influences the outcome of a new transaction. This unpredictability is unacceptable in most circumstances.
U.S. provisional application 60/208,268 filed 31 May 2000 in the name of IBM Corporation discloses the idea of having two heaps in a JVM. One of these is a transient heap, which is used to store transaction objects that will not persist into the next transaction, whilst a second, persistent, heap is used for storing objects, such as system objects, that will persist. This approach provides the basis for an efficient reset mechanism by deleting the transient heap. This concept is developed in GB application 0027045.4, filed 6 Nov. 2000 in the name of IBM Corporation, which focuses particularly on the deletion of the transient heap. One difficulty that arises at reset is how to handle pointers from objects in the persistent heap to objects in the transient heap, since following reset and deletion of the transient heap, these pointers will no longer be valid. The general policy in the above application is that if such cross-heap pointers exist, the Java VM is no longer resettable, and so will normally have to be terminated.
However, it is possible that the objects in the persistent heap from which the cross-heap pointers originate are no longer live, but rather are waiting to be garbage collected (the process of garbage collection in Java is described in more detail below). It is clearly undesirable to terminate the Java VM as unresettable simply on the basis of a cross-heap pointer that could possibly be deleted. Therefore, as described in the above application, if any cross-heap pointers are found at reset, a garbage collection operation is performed, which will remove any objects that are no longer live. In many cases this will eliminate all the objects that have the cross-heap pointers, thereby allowing reset to proceed.
Although the approach in the GB 0027045.4 application is effective, it suffers from the problem that garbage collection is a relatively time-consuming operation. Thus if any cross-heap pointers are found, there is a significant wait while the garbage collection is performed in order to determine whether or not the Java VM is safe to reset. This wait is unfortunate, given that one of the main motivations for being able to reset the Java VM in the first place was to overcome the start-up delay when having to launching a new Java VM for each transaction.